﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Web;

namespace EmbeddedSensorCloud.HTTP
{
    public sealed class Request
    {
        public readonly string Method;
        public readonly string Url;
        public readonly Version Version;
        public readonly Dictionary<string, string> Args;
        public readonly Dictionary<string, string> Headers;
        public readonly string Body;

        public Request(string method, string url, Version version, Dictionary<string, string> headers, Dictionary<string, string> args = null, string body = null)
        {
            this.Method = method;
            this.Url = url;
            this.Version = version;
            this.Headers = headers;
            this.Args =  args ?? new Dictionary<string, string>();
            this.Body = body;
        }

        public static Request Parse(NetworkStream inputStream)
        {
            var reader = new StreamReader(inputStream);
            var httpEntrance = reader.ReadLine();

            var tokens = httpEntrance.Split(' ');
            if (tokens.Length != 3)
            {
                throw new Exception("Invalid http request line: " + httpEntrance);
            }

            var method = tokens[0].ToUpper();
            var url = Helper.TooUrlWithoutArguments(tokens[1]);
            var version = Helper.ToHTTPVersion(tokens[2]);

            var headers = new Dictionary<string, string>();
            String line;
            while (!string.IsNullOrWhiteSpace(line = reader.ReadLine()))
            {
                try
                {
                    var head = Helper.ToHeader(line);
                    headers[head.Key] = head.Value;
                }
                catch
                {
                    continue;
                }
            }

            string argumentLine = tokens[1];
            string body = null;

            string contentLengthRaw = null;
            int contentLength;
            
            if (headers.TryGetValue("Content-Length", out contentLengthRaw) && Int32.TryParse(contentLengthRaw, out contentLength) && contentLength > 0)
            {
                string contentType;
                if (!headers.TryGetValue("Content-Type", out contentType))
                {
                    throw new Exception("Invalid request. Content-Type header is missing");
                }

                char[] postArray = new char[contentLength];
                reader.ReadBlock(postArray, 0, contentLength);
                var content = new string(postArray);

                if (contentType == "application/x-www-form-urlencoded")
                {
                    argumentLine += "?" + content;
                }
                else
                {
                    body = content;
                }
            }

            var parameters = Helper.ToArguments(argumentLine);
            return new Request(method, url, version, headers, parameters, body);
        }
    }
}
